'''
@author: saaj
@license: LGPL
'''


import test
import types
import unittest
import cherrypy
import glob
import os.path
import shutil
from application import model


test.initialize("test_suite")


class TestModel(unittest.TestCase):
  
  testee = None
  
  
  def setUp(self):
    cherrypy.thread_data.db.autocommit(False)
  
  def tearDown(self):
    cherrypy.thread_data.db.rollback()

  def testMethodCoverage(self):
    if self.__class__ is TestModel:
      return
    
    def methods(object):
      return {
        name for (name, value) in object.__class__.__dict__.items() 
        if isinstance(value, types.FunctionType) and name[0] != "_"
      }
    
    self.assertFalse(self.testee is None, "Testee must be created in setUp()")
    
    diff = set("test" + name[0].upper() + name[1:] for name in methods(self.testee)) - methods(self) 
    self.assertEqual(0, len(diff), "Test case misses: {0}".format(", ".join(diff)))


class TestNode(TestModel):
  
  def setUp(self):
    self.testee = model.Note()
    super(TestNode, self).setUp()

  def testCount(self):
    self.assertEqual(4, self.testee.count())
  
  def testRange(self):
    expected = (
    {
      'noteId'  : 6, 
      'name'    : 'note#1',
      'comment' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' 
    }, 
    {
      'noteId' : 7, 
      'name'   : 'note#2',
      'comment': 'Phasellus aliquam venenatis velit nec malesuada.'
    })
    
    self.assertEqual(expected, self.testee.range(0, 1))
  
  def testCreate(self):
    self.assertEqual(4, self.testee.count())
    
    self.testee.create("test", "test test test")
    actual = self.testee.range(4, 5)[0]
    self.assertEqual({
      'noteId'  : actual["noteId"], 
      'name'    : 'test',
      'comment' : 'test test test' 
    }, actual)
    
    self.assertEqual(5, self.testee.count())
    
  def testRemove(self):
    self.assertEqual(4, self.testee.count())
    
    self.testee.remove(8)
    
    self.assertEqual(3, self.testee.count())
    

class TestFile(TestModel):
  
  def setUp(self):
    for source in glob.glob(cherrypy.thread_data.path + "/application/*"):
      destination = os.path.join(cherrypy.thread_data.path, "variable/storage", os.path.basename(source))
      shutil.copy(source, destination)
      
    self.testee = model.File()
    
  def tearDown(self):
    map(os.remove, glob.glob(cherrypy.thread_data.path + "/variable/storage/*")) 
    
  def testList(self):
    expected = ('controller.py', 'model.py', 'service.py', '__init__.py')
    actual   = set(item["name"] for item in self.testee.list())
    self.assertTrue(all(name in actual for name in expected))
  
  def testGet(self):
    self.assertEqual("__init__.py", os.path.basename(self.testee.get("__init__.py").name))
    
  def testPut(self):
    filename = cherrypy.thread_data.path + "/application/__init__.py"
    with open(filename, "rb") as f:
      self.testee.put("test.test", f)
      
      files = {item["name"] : item for item in self.testee.list()}
      self.assertTrue("test.test" in files)
      self.assertGreater(files["test.test"]["size"], 128)
    
  def testRemove(self):
    self.testee.remove("model.py")
    files = set(item["name"] for item in self.testee.list())
    self.assertTrue("model.py" not in files)